home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
TPUG - Toronto PET Users Group
/
TPUG Users Group CD
/
TPUG Users Group CD.iso
/
AMIGA
/
(A)TA
/
(A)TAJ.ADF
/
Othello
/
CSOthello.c
< prev
next >
Wrap
C/C++ Source or Header
|
1986-11-06
|
44KB
|
1,893 lines
#include <exec/types.h>
#include <lattice/stdio.h>
#include <intuition/intuition.h>
#define VERSION 1
#define MAXBOXES 12
#define MAXLOOK 10
#define WIDE 64 * 2
#define HIGH 512
#define LINEHEIGHT 10
#define XBORDER 6
#define YBORDER 3
#define BOXIT TRUE
#define NOBOXIT FALSE
#define IDCMPNORMAL CLOSEWINDOW | MENUPICK | MOUSEBUTTONS
#define DISKDEFNAME "Othello.def"
#include <othmenu.h>
#define EMPTY 0
#define BLACK 1
#define RED 2
#define OFFSCREEN 3
#define DEFAULTP1 HUMAN
#define DEFAULTP2 HUMAN
#define DEFAULTSIZE 8
#define DEFAULTGURUWAIT STEPTHROUGH
struct Image logo =
{
0, 0,
POINTERWIDTH * 2, POINTERHEIGHT, 2,
NULL,
3, 0,
NULL
};
USHORT ourpointerdata[] =
{
0x0000, 0x0000,
0x0000, 0x3000,
0x0000, 0x4800,
0x0000, 0x4000,
0x0080, 0x4000,
0x0080, 0x4000,
0x02A0, 0x4800,
0x01C0, 0x3000,
0x0080, 0x0000,
0x1004, 0x1004,
0x0808, 0x0808,
0x7C1F, 0x7C9F,
0x0808, 0x0808,
0x1004, 0x1004,
0x0080, 0x0000,
0x01C0, 0x0006,
0x02A0, 0x0009,
0x0080, 0x0008,
0x0080, 0x0006,
0x0000, 0x0001,
0x0000, 0x0009,
0x0000, 0x0006,
0x0000, 0x0000
};
USHORT *ourpointer = 0;
ULONG *ourlongpointer;
ULONG expand();
extern struct Menu Titles[];
extern struct MenuItem Items[];
extern struct MenuItem SubItems[];
struct IntuitionBase *IntuitionBase = NULL;
struct GfxBase *GfxBase = NULL;
struct Window *window = NULL;
unsigned char *circle = NULL;
struct IntuiMessage *message;
char gamebuffer[MAXLOOK][MAXBOXES+2][MAXBOXES+2];
char *game[MAXLOOK][MAXBOXES+2];
short looksp1, looksp2;
short whoseturn;
short guruwait;
BOOL workbench;
short whostarts = BLACK;
ULONG class;
short xoffset, yoffset, ytextoff;
short xthought, ythought;
short scores[3];
short width, height;
short numboxes, boxheight, boxwidth;
BOOL stuck, newgame;
char bonus[MAXBOXES+2][MAXBOXES+2];
struct IntuiText Quittext =
{
2,1,
JAM2,
23,10,
NULL,
" Really Quit?",
NULL
};
struct IntuiText Postext =
{
2,1,
JAM2,
6,3,
NULL,
"Yes",
NULL
};
struct IntuiText Negtext =
{
2,1,
JAM2,
6,3,
NULL,
"No Way!",
NULL
};
struct Image textplayer =
{
0, 0, /* leftedge, topedge */
16, 8, 1, /* width, height, depth */
NULL, /* image data pointer */
1, 0, /* planepick, planeonoff */
NULL /* next image */
};
struct Image player =
{
5, 2, /* leftedge, topedge */
0, 0, 1, /* width, height, depth */
NULL, /* image data pointer */
1, 0, /* planepick, planeonoff */
NULL /* next image */
};
UBYTE *yourmove = "Your move, player . ";
UBYTE *cantmove = "Player can't move. ";
UBYTE *victory = "Player wins. ";
UBYTE *tiegame = "The game is a tie. ";
UBYTE *finished = "Game over. ";
UBYTE *neither = "Neither player can move. ";
UBYTE *scoreis = " ";
UBYTE *notempty = "That square is already taken. ";
UBYTE *notlegal = "That is not a legal move. ";
UBYTE *bestmove = "This is your best move. ";
UBYTE *youcant = "You can't move. ";
UBYTE *possible = "These are all the possible moves.";
UBYTE *blank = " ";
UBYTE *thinking = "Please wait - I'm thinking. ";
UBYTE *click = "Click in window to continue. ";
UBYTE *openfail = "File could not be opened. ";
UBYTE *illvalue = "Illegal value in file. ";
UBYTE *shortfil = "Invalid data file. Too short. ";
UBYTE *loaded = "Game loaded. ";
UBYTE *saved = "Game saved. ";
UBYTE *writfail = "Write to file failed. ";
UBYTE *defsaved = "Defaults saved. ";
ULONG powers[32];
struct TextAttr smallfont =
{
"Topaz80",8,0,0
};
struct IntuiText string =
{
1, 0, /* frontpen, backpen */
JAM2, /* drawmode */
0,0, /* leftedge, topedge */
&smallfont, /* pointer to font */
NULL, /* pointer to text data */
NULL /* next text */
};
short squarepoints[10];
short smallsquarepoints[10];
struct Border square =
{
0, 0, /* leftedge, topedge */
2, 0, JAM1, /* frontpen, backpen, drawmode */
5, /* count */
squarepoints, /* xy data */
NULL /* next border */
};
struct Border smallsquare =
{
0, 0, /* leftedge, topedge */
1, 0, JAM1, /* frontpen, backpen, drawmode */
5, /* count */
smallsquarepoints, /* xy data */
NULL /* next border */
};
struct Border xline =
{
0, 0, /* leftedge, topedge */
3, 0, JAM1, /* frontpen, backpen, drawmode */
2, /* count */
squarepoints, /* xy data */
NULL /* next border */
};
struct Border yline =
{
0, 0, /* leftedge, topedge */
3, 0, JAM1, /* frontpen, backpen, drawmode */
2, /* count */
squarepoints + 6, /* xy data */
NULL /* next border */
};
struct NewWindow newwindow =
{
0,0,
330,185,
-1,-1,
IDCMPNORMAL,
WINDOWDEPTH | WINDOWDRAG | WINDOWCLOSE | SMART_REFRESH | ACTIVATE,
NULL,
NULL,
"CSOthello - ⌐ CygnusSoft.",
NULL,
NULL,
330,185,
330,185,
WBENCHSCREEN
};
main(argc,argv)
int argc;
char *argv[];
{
short r, x, y, level;
powers[0] = 1;
for (x = 1; x < 32; x++)
powers[x] = powers[x-1] * 2;
workbench = (argc == 0);
if (!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 29)))
quit_cleanup("Can't open Intuition Library.");
if (!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",29)))
quit_cleanup("Can't open Graphics library.");
if (!(window = (struct Window *)OpenWindow(&newwindow)))
quit_cleanup("Can't open the window.");
xoffset = window->BorderLeft + XBORDER;
ytextoff = window->BorderTop + YBORDER;
yoffset = ytextoff + 3 * LINEHEIGHT + YBORDER;
width = window->Width - xoffset - window->BorderRight - XBORDER;
height = window->Height - yoffset - window->BorderBottom - YBORDER;
string.LeftEdge = xoffset;
string.TopEdge = ytextoff;
getdefaults(); /* must be called before set menu strip,
but after assigning xoffset, ytextoff */
SetMenuStrip(window, Titles);
if (ourpointer = (USHORT *)AllocRaster(POINTERWIDTH*2,POINTERHEIGHT*2))
{
ourlongpointer = (ULONG *)ourpointer;
for (y = 0; y < POINTERHEIGHT; y++)
{
ourlongpointer[y] = expand(ourpointerdata[y * 2 + 2]);
/* ourpointer[y] = ourpointerdata[y * 2 + 2];
ourpointer[y + POINTERHEIGHT] = ourpointerdata[y * 2 + 3]; */
ourlongpointer[y + POINTERHEIGHT] = expand(ourpointerdata[y * 2 + 3]);
}
logo.ImageData = ourpointer;
DrawImage(window->RPort, &logo, xoffset + width - 32, ytextoff);
for (y = 0; y < (POINTERHEIGHT + 2) * 2; y++)
ourpointer[y] = ourpointerdata[y];
SetPointer(window,ourpointer,POINTERHEIGHT,POINTERWIDTH,POINTERXOFF,POINTERYOFF);
}
if (!(circle = (unsigned char *)AllocRaster(WIDE, HIGH)))
quit_cleanup("Can't allocate raster data.");
for (r = 4; r <= 4; r++)
generatecircle(r, circle + (r-1)*256);
textplayer.ImageData = (short *)&circle[256 * 3];
for (level = 0; level < MAXLOOK; level++)
for (x = 0; x < MAXBOXES + 2; x++)
game[level][x] = gamebuffer[level][x];
initialize();
info(PROJECT, ABOUT, NULL);
while (TRUE)
{
showplayer(whoseturn, 141, 0);
if (moveable(whoseturn)) /* the player can move */
{
stuck = FALSE;
if (whoseturn == BLACK)
domoveblack();
else domovered();
}
else if (stuck == TRUE) /* neither player can move */
endgame();
else /* one, maybe two, players can move */
{
printstring(cantmove, 0, LINEHEIGHT);
showplayer(whoseturn, 52, LINEHEIGHT);
stuck = TRUE;
whoseturn = BLACK + RED - whoseturn; /*must be done before wait*/
if (whoseturn == BLACK && looksp1 == HUMAN && looksp2 != HUMAN)
waitforclick(FALSE,FALSE);
else if (whoseturn == RED && looksp1 != HUMAN && looksp2 == HUMAN)
waitforclick(FALSE,FALSE);
else if (looksp1 != HUMAN && looksp1 != HUMAN && guruwait == STEPTHROUGH)
waitforclick(TRUE,FALSE);
}
}
}
ULONG expand(word)
short word;
{
short bit;
ULONG answer;
answer = 0;
for (bit = 0; bit < 16; bit++)
if (powers[bit] & word)
answer |= (powers[bit * 2] * 3);
return(answer);
}
showplayer(current, x, y)
short current, x, y;
{
textplayer.PlanePick = current;
DrawImage(window->RPort, &textplayer, xoffset + x, ytextoff + y);
}
generatecircle(r, p)
short r;
unsigned char *p;
{
short x, y, rsquared, wordwidth;
short tx, ty;
for (x = 0; x < 8 * 32; x++)
p[x] = 0;
rsquared = r * r * 4 + 2;
wordwidth = (((r * 4) + 15) / 16) * 2;
for (x = 0; x < r * 2; x++)
for (y = 0; y < r; y++)
if ((x * x + y * y * 4) < rsquared)
{
ty = r + y;
tx = 2 * r + x;
p[ty * wordwidth + (tx / 8)] |= powers[7 - (tx & 7)];
ty = r - y - 1;
p[ty * wordwidth + (tx / 8)] |= powers[7 - (tx & 7)];
tx = 2 * r - x - 1;
ty = r + y;
p[ty * wordwidth + (tx / 8)] |= powers[7 - (tx & 7)];
ty = r - y - 1;
p[ty * wordwidth + (tx / 8)] |= powers[7 - (tx & 7)];
}
}
/* for debug purposes only
printarray(index)
short index;
{
short x, y;
for (y = 0; y <= numboxes + 1; y++)
{
for (x = 0; x <= numboxes + 1; x++)
printf("%d ", game[index][x][y]);
printf("\n");
}
} */
printscores()
{
sprintf(scoreis, "Score: %3d %3d", scores[BLACK], scores[RED]);
printstring(scoreis, 0, LINEHEIGHT * 2);
showplayer(BLACK, 68, LINEHEIGHT * 2);
showplayer(RED, 140, LINEHEIGHT * 2);
}
endgame()
{
printstring(blank, 0, LINEHEIGHT);
if (scores[RED] + scores[BLACK] < numboxes * numboxes)
printstring(neither, 0, 0);
else
printstring(finished, 0, 0);
if (scores[BLACK] > scores[RED])
{
printstring(victory, 0, LINEHEIGHT);
showplayer(BLACK, 52, LINEHEIGHT);
}
else if (scores[BLACK] < scores[RED])
{
printstring(victory, 0, LINEHEIGHT);
showplayer(RED, 52, LINEHEIGHT);
}
else
printstring(tiegame, 0, LINEHEIGHT);
newgame = FALSE;
while (TRUE)
{
WaitPort(window->UserPort);
message = (struct IntuiMessage *)GetMsg(window->UserPort);
processmessage();
if (newgame)
return(0);
}
}
think(level, colour, index)
short level, colour, index;
{
short bestx = 0, besty = 0;
short x, y, count = 0;
int best = -2000, temp;
BOOL moved = FALSE;
if (level == 0)
{
for ( x = 1; x <= numboxes; x++ )
for ( y = 1; y <= numboxes; y++ )
if (game[index][x][y] == EMPTY)
{
temp = move_i(x, y, colour, index);
if (temp > best)
{
best = temp;
bestx = x;
besty = y;
}
else if (temp == best && index == MAXLOOK-1 )
{
count++;
if (!(rand() % count))
{
best = temp;
bestx = x;
besty = y;
}
}
}
if (index == MAXLOOK - 1) /* if first level then */
{
xthought = bestx;
ythought = besty;
}
return(best);
}
for ( x = 1; x <= numboxes; x++ )
for ( y = 1; y <= numboxes; y++ )
if (game[index][x][y] == EMPTY)
{
temp = move_i(x, y, colour, index);
if (temp > 0)
{
moved = TRUE;
copyplot(index, x, y, colour);
temp = temp - think(level-1, RED + BLACK - colour, index-1);
if (temp > best)
{
best = temp;
bestx = x;
besty = y;
count = 1;
}
else if (temp == best && index == MAXLOOK-1 )
{
count++;
if (!(rand() % count))
{
best = temp;
bestx = x;
besty = y;
}
}
}
}
if (!(moved)) /* if colour cannot make a move then */
{
copy(index);
best = -think(level-1, RED + BLACK - colour, index - 1);
}
if (index == MAXLOOK - 1) /* if first level then */
{
xthought = bestx;
ythought = besty;
}
return(best);
}
dumbthink(level, colour, index)
short level, colour, index;
{
short x, y, count = 0;
int worst = 4000, temp; /* the initial value of worst must be greater
than the absolute value of the initial value of best
in think in order to avoid deadlock on the last few
moves. */
/* this routine finds the worst move possible. Since it is always called as
the first level ( then it calls think() ) many checks can be dispensed with.
We know there must be a move because otherwise this routine would not have
been called. */
if (level == 0)
{
for ( x = 1; x <= numboxes; x++ )
for ( y = 1; y <= numboxes; y++ )
if (game[index][x][y] == EMPTY)
{
temp = move_i(x, y, colour, index);
if (temp)
if (temp < worst)
{
worst = temp;
xthought = x;
ythought = y;
}
else if (temp == worst)
{
count++;
if (!(rand() % count))
{
worst = temp;
xthought = x;
ythought = y;
}
}
}
return(worst);
}
for ( x = 1; x <= numboxes; x++ )
for ( y = 1; y <= numboxes; y++ )
if (game[index][x][y] == EMPTY)
{
temp = move_i(x, y, colour, index);
if (temp > 0)
{
copyplot(index, x, y, colour);
temp = temp - think(level-1, RED + BLACK - colour, index-1);
if (temp < worst)
{
worst = temp;
xthought = x;
ythought = y;
count = 1;
}
else if (temp == worst)
{
count++;
if (!(rand() % count))
{
worst = temp;
xthought = x;
ythought = y;
}
}
}
}
return(worst);
}
copyplot(index, x, y, colour)
short index, x, y, colour;
{
short opponent;
int count;
short count2, dx, dy, xcopy, ycopy, i;
opponent = BLACK + RED - colour;
copy(index);
count = 0;
if (game[index-1][x][y] != EMPTY)
quit_cleanup("Error. Can't plot in filled box.");
for (dx = -1; dx <= 1; dx++)
for (dy = -1; dy <= 1; dy++)
{
xcopy = x + dx;
ycopy = y + dy;
count2 = 0;
while ( game[index-1][xcopy][ycopy] == opponent )
{
count2++;
xcopy = xcopy + dx;
ycopy = ycopy + dy;
}
if (game[index-1][xcopy][ycopy] == colour)
{
count = count + count2;
for ( i = 1; i <= count2; i++)
{
xcopy = xcopy - dx;
ycopy = ycopy - dy;
game[index-1][xcopy][ycopy] = colour;
}
}
}
if (count)
game[index-1][x][y] = colour;
else
quit_cleanup("Error. Illegal move by think.");
}
copy(index)
short index;
{
short dx, dy;
for ( dx = 1; dx <= numboxes; dx++ )
for ( dy = 1; dy <= numboxes; dy++ )
game[index-1][dx][dy] = game[index][dx][dy];
}
waitforclick(resume,printit)
BOOL resume; /* whether or not to resume if mode change to RACETHROUGH */
BOOL printit; /* whether or not to print click message */
{
struct IntuiMessage *message;
if (scores[RED] + scores[BLACK] >= numboxes * numboxes)
return(0);
if (printit)
printstring(click, 0, LINEHEIGHT);
newgame = FALSE;
while (TRUE)
{
clearport();
WaitPort(window->UserPort);
message = (struct IntuiMessage *)GetMsg(window->UserPort);
if ( message->Class == MOUSEBUTTONS && message->Code == SELECTDOWN )
{
ReplyMsg(message);
return(0);
}
else
processmessage();
if ((guruwait == RACETHROUGH && resume) || newgame)
return(0);
}
}
domovered()
{
short x, y;
USHORT code;
if (looksp2 != HUMAN)
{
printstring(thinking, 0, LINEHEIGHT);
if (looksp2 < LEVELM1)
think(looksp2, RED, MAXLOOK-1);
else
dumbthink(looksp2-LEVELM1, RED, MAXLOOK-1);
flip(xthought, ythought, RED);
clearport();
if (guruwait == STEPTHROUGH && looksp1 != HUMAN)
{
showplayer(whoseturn, 141, 0);
waitforclick(TRUE,TRUE);
}
}
else
{
WaitPort(window->UserPort);
message = (struct IntuiMessage *)GetMsg(window->UserPort);
if (message->Class == MOUSEBUTTONS)
{
x = message->MouseX;
y = message->MouseY;
code = message->Code;
ReplyMsg(message);
mouseclick(RED, x, y, code);
}
else
processmessage();
}
}
domoveblack()
{
short x, y;
USHORT code;
if (looksp1 != HUMAN)
{
printstring(thinking, 0, LINEHEIGHT);
if (looksp1 < LEVELM1)
think(looksp1, BLACK, MAXLOOK-1);
else
dumbthink(looksp1-LEVELM1, BLACK, MAXLOOK-1);
flip(xthought, ythought, BLACK);
clearport();
if (guruwait == STEPTHROUGH && looksp2 != HUMAN)
{
showplayer(whoseturn, 141, 0);
waitforclick(TRUE,TRUE);
}
}
else
{
WaitPort(window->UserPort);
message = (struct IntuiMessage *)GetMsg(window->UserPort);
if (message->Class == MOUSEBUTTONS)
{
x = message->MouseX;
y = message->MouseY;
code = message->Code;
ReplyMsg(message);
mouseclick(BLACK, x, y, code);
}
else
processmessage();
}
}
mouseclick(current, x, y, code)
short current, x, y;
USHORT code;
{
struct IntuiMessage *message;
short nx, ny;
if (code != SELECTDOWN)
return(0);
nx = x - xoffset;
ny = y - yoffset;
x = nx / boxwidth;
y = ny / boxheight;
while (code != SELECTUP)
{
WaitPort(window->UserPort);
message = (struct IntuiMessage *)GetMsg(window->UserPort);
code = message->Code;
nx = message->MouseX - xoffset;
ny = message->MouseY - yoffset;
ReplyMsg(message);
}
if (x != (nx / boxwidth))
return(0);
if (y != (ny / boxheight))
return(0);
if (nx < 0 || ny < 0 || x >= numboxes || y >= numboxes)
return(0);
return(flip(x+1,y+1,current));
}
flip(x,y,current)
short x, y, current;
{
int count;
short count2, dx, dy, xcopy, ycopy, i;
short opponent;
printstring(blank, 0 ,LINEHEIGHT);
opponent = RED + BLACK - current;
count = 0;
if (game[MAXLOOK-1][x][y] != EMPTY)
{
printstring(notempty, 0, LINEHEIGHT);
return(0);
}
for (dx = -1; dx <= 1; dx++)
for (dy = -1; dy <= 1; dy++)
{
xcopy = x + dx;
ycopy = y + dy;
count2 = 0;
while ( game[MAXLOOK-1][xcopy][ycopy] == opponent )
{
count2++;
xcopy = xcopy + dx;
ycopy = ycopy + dy;
}
if (game[MAXLOOK-1][xcopy][ycopy] == current)
{
count = count + count2;
for ( i = 1; i <= count2; i++)
{
xcopy = xcopy - dx;
ycopy = ycopy - dy;
plot(xcopy,ycopy,current,NOBOXIT);
}
}
}
if (count)
{
scores[current] = scores[current] + count + 1;
scores[opponent] = scores[opponent] - count;
plot(x,y,current,BOXIT);
whoseturn = RED + BLACK - whoseturn;
printscores();
}
else
printstring(notlegal, 0, LINEHEIGHT);
return(count);
}
moveable(current)
{
int moves;
short x, y;
moves = 0;
for ( x = 1; x <= numboxes; x++)
for (y = 1; y <= numboxes; y++)
moves = moves + move(x,y,current,MAXLOOK-1);
return(moves);
}
move(x,y,current,index)
short x, y, current, index;
{
int count;
short count2, dx, dy, xcopy, ycopy, opponent;
opponent = RED + BLACK - current;
count = 0;
if (game[index][x][y] != EMPTY)
return(0);
for (dx = -1; dx <= 1; dx++)
for (dy = -1; dy <= 1; dy++)
{
xcopy = x + dx;
ycopy = y + dy;
count2 = 0;
while ( game[index][xcopy][ycopy] == opponent )
{
count2++;
xcopy = xcopy + dx;
ycopy = ycopy + dy;
}
if (game[index][xcopy][ycopy] == current)
count = count + count2;
}
return(count);
}
move_i(x,y,current,index)
short x, y, current, index;
{
REGISTER unsigned long count, count2, opponent;
REGISTER char *p, *p2;
opponent = RED + BLACK - current;
count = 0;
p = &game[index][x][y];
/* We now look in each of the eight directions and find out how many (if
any) pieces we can flip over. I use pointers to directly access the members
of the array and I have separate code for each direction for efficiency
reasons. I'm only going to comment the first of the eight because the
comments for the others would be almost identical. The original code, using
nested for loops to look in all eight directions is shown at the bottom. */
/* check in the -x, -y direction */
p2 = p - (MAXBOXES+2 + 1); /* subtract 1 from x and y coordinates. */
if (*p2 == opponent) /* is neighbouring piece opponents? */
{
count2 = 1; /* set temporary flipped piece counter. */
p2 -= MAXBOXES+2 + 1; /* subtract 1 from x and y coordinates. */
while (*p2 == opponent) /* go to end of row of opponents. */
{
count2++; /* count the number of pieces passed over. */
p2 -= MAXBOXES+2 + 1; /* subtract 1 from x and y coordinate. */
}
if (*p2 == current) /* if own piece ends line then, */
count += count2; /* we can flip count pieces. */
}
/* check in the -y direction */
p2 = p - 1;
if (*p2 == opponent)
{
count2 = 1;
p2--;
while (*p2 == opponent)
{
count2++;
p2--;
}
if (*p2 == current)
count += count2;
}
/* check in the +x, -y direction */
p2 = p + (MAXBOXES+2) - 1;
if (*p2 == opponent)
{
count2 = 1;
p2 += MAXBOXES+2 - 1;
while (*p2 == opponent)
{
count2++;
p2 += MAXBOXES+2 - 1;
}
if (*p2 == current)
count += count2;
}
/* check in the -x direction */
p2 = p - (MAXBOXES+2);
if (*p2 == opponent)
{
count2 = 1;
p2 -= MAXBOXES+2;
while (*p2 == opponent)
{
count2++;
p2 -= MAXBOXES+2;
}
if (*p2 == current)
count += count2;
}
/* check in the +x direction */
p2 = p + MAXBOXES+2;
if (*p2 == opponent)
{
count2 = 1;
p2 += MAXBOXES+2;
while (*p2 == opponent)
{
count2++;
p2 += MAXBOXES+2;
}
if (*p2 == current)
count += count2;
}
/* check in the -x, +y direction */
p2 = p + 1 - (MAXBOXES+2);
if (*p2 == opponent)
{
count2 = 1;
p2 += 1 - (MAXBOXES+2);
while (*p2 == opponent)
{
count2++;
p2 += 1 - (MAXBOXES+2);
}
if (*p2 == current)
count += count2;
}
/* check in the +y direction */
p2 = p + 1;
if (*p2 == opponent)
{
count2 = 1;
p2++;
while (*p2 == opponent)
{
count2++;
p2++;
}
if (*p2 == current)
count += count2;
}
/* check in the +x, +y direction */
p2 = p + MAXBOXES+2 + 1;
if (*p2 == opponent)
{
count2 = 1;
p2 += MAXBOXES+2 + 1;
while (*p2 == opponent)
{
count2++;
p2 += MAXBOXES+2 + 1;
}
if (*p2 == current)
count += count2;
}
/* This is the older, easier to read, but slower, move_i routine
for (dx = -1; dx <= 1; dx++)
for (dy = -1; dy <= 1; dy++)
{
xcopy = x + dx;
ycopy = y + dy;
count2 = 0;
while ( game[index][xcopy][ycopy] == opponent )
{
count2++;
xcopy = xcopy + dx;
ycopy = ycopy + dy;
}
if (game[index][xcopy][ycopy] == current)
count = count + count2;
} */
if (count)
return(count + bonus[x][y]);
else
return(0);
}
plot(x,y,current,box)
short x, y, current;
BOOL box;
{
if ( x < 1 || x > numboxes || y < 1 || y > numboxes)
quit_cleanup("Illegal x or y value in plot call");
drawboard();
player.PlanePick = current;
game[MAXLOOK-1][x][y] = current;
if (box)
highlight(x, y);
x = xoffset + (x-1) * boxwidth;
y = yoffset + (y-1) * boxheight;
DrawImage(window->RPort, &player, x, y);
}
printstring(text, x, y)
char *text;
short x, y;
{
string.IText = text;
PrintIText(window->RPort, &string, x, y);
}
processmessage()
{
int menucode;
long class;
struct MenuItem *item;
class = message->Class;
menucode = message->Code;
ReplyMsg(message);
switch (class)
{
case CLOSEWINDOW :
ClearMenuStrip(window);
ModifyIDCMP(window,NULL);
if ( AutoRequest(window,&Quittext,&Postext,&Negtext,
NULL,NULL,180,57) )
{
SetMenuStrip(window,Titles);
quit_cleanup(0);
}
ModifyIDCMP(window,IDCMPNORMAL);
SetMenuStrip(window,Titles);
break;
case MENUPICK :
while (menucode != MENUNULL)
{
item = (struct MenuItem *)ItemAddress(Titles, menucode);
processmenu(MENUNUM(menucode), ITEMNUM(menucode), SUBNUM(menucode));
menucode = item->NextSelect;
}
break;
default :
break;
}
}
processmenu(menu, item, subitem)
int menu, item, subitem;
{
switch(menu)
{
case PROJECT :
switch (item)
{
case NEWGAME :
whostarts = subitem + 1;
initialize();
break;
case BOARDSIZE :
if (numboxes != 6 + subitem * 2)
{
numboxes = 6 + subitem * 2;
initialize();
}
break;
case OPEN :
loadgame();
break;
case SAVEGAME :
savegame();
break;
case SAVEDEF :
savedefaults();
break;
case ABOUT :
info(menu,item,subitem);
break;
case HELP :
switch (subitem)
{
case FUNCTION :
helpfunction();
break;
case ALL :
info(menu,item,subitem);
break;
}
break;
case QUIT :
ClearMenuStrip(window);
ModifyIDCMP(window,NULL);
if ( AutoRequest(window,&Quittext,&Postext,&Negtext,
NULL,NULL,180,57) )
{
SetMenuStrip(window,Titles);
quit_cleanup(0);
}
ModifyIDCMP(window,IDCMPNORMAL);
SetMenuStrip(window,Titles);
break;
}
break;
case PLAYER1 :
looksp1 = item;
break;
case PLAYER2 :
looksp2 = item;
break;
case GURUVSGURU :
guruwait = item;
break;
case OTHER :
switch (item)
{
case MOVES :
showmoves();
break;
case SUGGEST :
suggest();
break;
}
break;
}
}
extern BOOL info_display();
helpfunction()
{
struct IntuiMessage *message;
ULONG MessageClass;
USHORT WhichButton;
ModifyIDCMP(window, MENUPICK);
WaitPort(window->UserPort);
message = (struct IntuiMessage *)GetMsg(window->UserPort);
MessageClass = message->Class;
WhichButton = message->Code;
ReplyMsg(message);
while (WhichButton != MENUNULL)
{
struct MenuItem *item;
item = (struct MenuItem *)ItemAddress(Titles,WhichButton);
if (info(MENUNUM(WhichButton),
ITEMNUM(WhichButton),
SUBNUM(WhichButton)) == FALSE)
quit_cleanup("Info problem!!!\n");
WhichButton = item->NextSelect;
}
ModifyIDCMP(window,IDCMPNORMAL);
}
info(menu,item,subitem)
int menu,item,subitem;
{
ClearMenuStrip(window);
ModifyIDCMP(window,NULL);
info_display(menu,item,subitem);
checkit();
SetMenuStrip(window,Titles);
ModifyIDCMP(window, IDCMPNORMAL);
}
showmoves()
{
short x, y;
BOOL any = FALSE;
showplayer(whoseturn, 141, 0);
drawboard();
for (x = 1; x <= numboxes; x++)
for (y = 1; y <= numboxes; y++)
if (move(x,y,whoseturn,MAXLOOK-1))
{
any = TRUE;
highlight(x, y);
}
if (any)
printstring(possible, 0, LINEHEIGHT);
else
printstring(youcant, 0, LINEHEIGHT);
if (looksp1 != HUMAN && looksp2 != HUMAN && guruwait == RACETHROUGH)
WaitPort(window->UserPort);
}
suggest()
{
showplayer(whoseturn, 141, 0);
if (moveable(whoseturn))
{
printstring(thinking, 0, LINEHEIGHT);
think(2,whoseturn,MAXLOOK-1);
drawboard();
highlight(xthought, ythought);
printstring(bestmove, 0, LINEHEIGHT);
}
else
printstring(youcant, 0, LINEHEIGHT);
if (looksp1 != HUMAN && looksp2 != HUMAN && guruwait == RACETHROUGH)
WaitPort(window->UserPort);
}
highlight(x, y)
short x, y;
{
smallsquare.FrontPen = whoseturn;
x = xoffset + (x - 1) * boxwidth;
y = yoffset + (y - 1) * boxheight;
DrawBorder(window->RPort, &smallsquare, x, y);
}
checklooks(looks)
short looks;
{
if (looks < LEVEL1 || looks > HUMAN)
return(FALSE);
else
return(TRUE);
}
checksize(size)
short size;
{
if (size != 6 && size != 8 && size != 10 && size != 12)
return(FALSE);
else
return(TRUE);
}
checkguru(guru)
short guru;
{
if (guru != STEPTHROUGH && guru != RACETHROUGH)
return(FALSE);
else
return(TRUE);
}
checkwhose(whose)
short whose;
{
if (whose != BLACK && whose != RED)
return(FALSE);
else
return(TRUE);
}
loadgame()
{
FILE *fp, *fopen();
char *gamename, *getgamename();
short x, y;
short version, l_looksp1, l_looksp2, l_whoseturn, l_numboxes, l_guruwait;
short l_scores[3];
char l_board[MAXBOXES][MAXBOXES];
char temp;
gamename = getgamename();
if ((fp = fopen(gamename, "r")) == NULL)
{
printstring(openfail, 0, LINEHEIGHT);
return(FALSE);
}
if ((version = (short)(getc(fp))) == EOF)
{
printstring(shortfil, 0, LINEHEIGHT);
fclose(fp);
return(FALSE);
}
if ((l_looksp1 = (short)(getc(fp))) == EOF)
{
printstring(shortfil, 0, LINEHEIGHT);
fclose(fp);
return(FALSE);
}
if (!checklooks(l_looksp1))
{
printstring(illvalue, 0, LINEHEIGHT);
fclose(fp);
return(FALSE);
}
if ((l_looksp2 = (short)(getc(fp))) == EOF)
{
printstring(shortfil, 0, LINEHEIGHT);
fclose(fp);
return(FALSE);
}
if (!checklooks(l_looksp2))
{
printstring(illvalue, 0, LINEHEIGHT);
fclose(fp);
return(FALSE);
}
if ((l_numboxes = (short)(getc(fp))) == EOF)
{
printstring(shortfil, 0, LINEHEIGHT);
fclose(fp);
return(FALSE);
}
if (!checksize(l_numboxes))
{
printstring(illvalue, 0, LINEHEIGHT);
fclose(fp);
return(FALSE);
}
if ((l_guruwait = (short)(getc(fp))) == EOF)
{
printstring(shortfil, 0, LINEHEIGHT);
fclose(fp);
return(FALSE);
}
if (!checkguru(l_guruwait))
{
printstring(illvalue, 0, LINEHEIGHT);
fclose(fp);
return(FALSE);
}
l_scores[RED] = 0;
l_scores[BLACK] = 0;
if ((l_whoseturn = (short)(getc(fp))) == EOF)
{
printstring(shortfil, 0, LINEHEIGHT);
fclose(fp);
return(FALSE);
}
if (!checkwhose(l_whoseturn))
{
printstring(illvalue, 0, LINEHEIGHT);
fclose(fp);
return(FALSE);
}
for (x=1; x<=l_numboxes; x++)
for (y=1; y<=l_numboxes; y++)
{
if ((temp = (short)(getc(fp))) == EOF)
{
printstring(shortfil, 0, LINEHEIGHT);
fclose(fp);
return(FALSE);
}
if (temp != EMPTY && temp != BLACK && temp != RED)
{
printstring(illvalue, 0, LINEHEIGHT);
fclose(fp);
return(FALSE);
}
l_board[x][y] = temp;
l_scores[l_board[x][y]]++;
}
fclose(fp);
looksp1 = l_looksp1;
looksp2 = l_looksp2;
whoseturn = l_whoseturn;
guruwait = l_guruwait;
numboxes = l_numboxes;
initialize();
for (x=1; x<=numboxes; x++)
for (y=1; y<=numboxes; y++)
{
plot(x,y,l_board[x][y],NOBOXIT);
}
scores[RED] = l_scores[RED];
scores[BLACK] = l_scores[BLACK];
printscores();
ClearMenuStrip(window);
checkit();
SetMenuStrip(window,Titles);
printstring(loaded, 0, LINEHEIGHT);
}
savegame()
{
FILE *fp, *fopen();
char *gamename, *getgamename();
short x, y;
gamename = getgamename();
if ((fp = fopen(gamename, "w")) == NULL)
{
printstring(openfail, 0, LINEHEIGHT);
return(FALSE);
}
if (putc(VERSION,fp) == EOF)
{
printstring(writfail, 0, LINEHEIGHT);
fclose(fp);
return(FALSE);
}
if (putc((char)(looksp1),fp) == EOF)
{
printstring(writfail, 0, LINEHEIGHT);
fclose(fp);
return(FALSE);
}
if (putc((char)(looksp2),fp) == EOF)
{
printstring(writfail, 0, LINEHEIGHT);
fclose(fp);
return(FALSE);
}
if (putc((char)(numboxes),fp) == EOF)
{
printstring(writfail, 0, LINEHEIGHT);
fclose(fp);
return(FALSE);
}
if (putc((char)(guruwait),fp) == EOF)
{
printstring(writfail, 0, LINEHEIGHT);
fclose(fp);
return(FALSE);
}
if (putc((char)(whoseturn),fp) == EOF)
{
printstring(writfail, 0, LINEHEIGHT);
fclose(fp);
return(FALSE);
}
for (x=1; x <= numboxes; x++)
for (y=1; y <= numboxes; y++)
if (putc(game[MAXLOOK-1][x][y],fp) == EOF)
{
printstring(writfail, 0, LINEHEIGHT);
fclose(fp);
return(FALSE);
}
fclose(fp);
printstring(saved, 0, LINEHEIGHT);
return(TRUE);
}
char *getgamename()
{
return("Othello.sav");
}
savedefaults()
{
FILE *fp, *fopen();
if ((fp = fopen( DISKDEFNAME, "w")) == NULL)
{
printstring(openfail, 0, LINEHEIGHT);
return(FALSE);
}
if (putc(VERSION,fp) == EOF)
{
printstring(writfail, 0, LINEHEIGHT);
fclose(fp);
return(FALSE);
}
if (putc((char)(looksp1),fp) == EOF)
{
printstring(writfail, 0, LINEHEIGHT);
fclose(fp);
return(FALSE);
}
if (putc((char)(looksp2),fp) == EOF)
{
printstring(writfail, 0, LINEHEIGHT);
fclose(fp);
return(FALSE);
}
if (putc((char)(numboxes),fp) == EOF)
{
printstring(writfail, 0, LINEHEIGHT);
fclose(fp);
return(FALSE);
}
if (putc((char)(guruwait),fp) == EOF)
{
printstring(writfail, 0, LINEHEIGHT);
fclose(fp);
return(FALSE);
}
fclose(fp);
printstring(defsaved, 0, LINEHEIGHT);
return(TRUE);
}
checkit()
{
short ordinal, x;
ordinal = 1 + STARTP2;
for (x = 0; x <= SQUARE12; x++)
SubItems[ordinal+x].Flags &= ~CHECKED;
SubItems[ordinal + ((numboxes-6)/2)].Flags |= CHECKED;
ordinal = 1 + QUIT;
for (x = 0; x <= HUMAN; x++)
Items[ordinal+x].Flags &= ~CHECKED;
Items[ordinal+looksp1].Flags |= CHECKED;
ordinal += 1 + HUMAN;
for (x = 0; x <= HUMAN; x++)
Items[ordinal+x].Flags &= ~CHECKED;
Items[ordinal+looksp2].Flags |= CHECKED;
ordinal += 1 + HUMAN;
for (x = 0; x <= RACETHROUGH; x++)
Items[ordinal+x].Flags &= ~CHECKED;
Items[ordinal+guruwait].Flags |= CHECKED;
}
getdefaults()
{
looksp1 = DEFAULTP1;
looksp2 = DEFAULTP2;
numboxes = DEFAULTSIZE;
guruwait = DEFAULTGURUWAIT;
getdiskdefaults();
checkit();
}
getdiskdefaults()
{
FILE *fp, *fopen();
short version, l_looksp1, l_looksp2, l_numboxes, l_guruwait;
if ((fp = fopen( DISKDEFNAME, "r" )) == NULL)
return(0);
if ((version = (short)(getc(fp))) == EOF)
{
printstring(shortfil, 0, LINEHEIGHT);
return(FALSE);
}
if ((l_looksp1 = (short)(getc(fp))) == EOF)
{
printstring(shortfil, 0, LINEHEIGHT);
return(FALSE);
}
if (!checklooks(l_looksp1))
{
printstring(illvalue, 0, LINEHEIGHT);
return(FALSE);
}
if ((l_looksp2 = (short)(getc(fp))) == EOF)
{
printstring(shortfil, 0, LINEHEIGHT);
return(FALSE);
}
if (!checklooks(l_looksp2))
{
printstring(illvalue, 0, LINEHEIGHT);
return(FALSE);
}
if ((l_numboxes = (short)(getc(fp))) == EOF)
{
printstring(shortfil, 0, LINEHEIGHT);
return(FALSE);
}
if (!checksize(l_numboxes))
{
printstring(illvalue, 0, LINEHEIGHT);
return(FALSE);
}
if ((l_guruwait = (short)(getc(fp))) == EOF)
{
printstring(shortfil, 0, LINEHEIGHT);
return(FALSE);
}
if (!checkguru(l_guruwait))
{
printstring(illvalue, 0, LINEHEIGHT);
return(FALSE);
}
fclose(fp);
looksp1 = l_looksp1;
looksp2 = l_looksp2;
numboxes = l_numboxes;
guruwait = l_guruwait;
return(0);
}
clearport()
{
struct IntuiMessage *message;
while (message = (struct IntuiMessage *)GetMsg(window->UserPort))
{
if (message->Class == MOUSEBUTTONS)
ReplyMsg(message);
else
processmessage(message);
}
}
quit_cleanup(x)
char *x;
{
if (circle)
FreeRaster(circle,WIDE,HIGH);
if (ourpointer)
FreeRaster(ourpointer,POINTERWIDTH*2,POINTERHEIGHT*2);
if (window)
{
ClearMenuStrip(window);
CloseWindow(window);
}
if (GfxBase)
CloseLibrary(GfxBase);
if (IntuitionBase)
CloseLibrary(IntuitionBase);
if (!(workbench) && x)
printf("%s\n",x);
exit(0);
}
drawboard()
{
short i;
for (i = 1; i < numboxes; i++)
{
DrawBorder(window->RPort,&xline,xoffset,yoffset+i*boxheight);
DrawBorder(window->RPort,&yline,xoffset+i*boxwidth,yoffset);
}
DrawBorder(window->RPort, &square, xoffset, yoffset);
}
initialize()
{
short x, y, r;
newgame = TRUE;
printstring(blank, 0, LINEHEIGHT);
whoseturn = whostarts;
boxheight = height / numboxes;
boxwidth = width / numboxes;
r = (boxheight - 2) / 2;
player.Width = r * 4;
player.Height = r * 2;
generatecircle(r, circle + (r - 1) * 256);
player.ImageData = (short *)&circle[256 * (r - 1)];
stuck = FALSE;
for (r = 0; r <= MAXLOOK-1; r++)
for (x = 0; x <= numboxes + 1; x++)
for (y = 0; y <= numboxes + 1; y++)
game[r][x][y] = OFFSCREEN;
for (x = 1; x <= numboxes; x++)
for (y = 1; y <= numboxes; y++)
game[MAXLOOK-1][x][y] = EMPTY;
squarepoints[0] = squarepoints[1] = 0;
squarepoints[2] = squarepoints[4] = numboxes * boxwidth;
squarepoints[5] = squarepoints[7] = numboxes * boxheight;
squarepoints[3] = squarepoints[6] = 0;
squarepoints[8] = squarepoints[9] = 0;
smallsquarepoints[0] = smallsquarepoints[1] = 0;
smallsquarepoints[2] = smallsquarepoints[4] = boxwidth;
smallsquarepoints[5] = smallsquarepoints[7] = boxheight;
smallsquarepoints[3] = smallsquarepoints[6] = 0;
smallsquarepoints[8] = smallsquarepoints[9] = 0;
SetAPen(window->RPort, 0);
RectFill(window->RPort,xoffset,yoffset,xoffset+width+1,yoffset+height+1);
drawboard();
game[MAXLOOK-1][numboxes/2][numboxes/2] = RED;
game[MAXLOOK-1][numboxes/2+1][numboxes/2+1] = RED;
game[MAXLOOK-1][numboxes/2+1][numboxes/2] = BLACK;
game[MAXLOOK-1][numboxes/2][numboxes/2+1] = BLACK;
scores[RED] = 2;
scores[BLACK] = 2;
printscores();
plot(numboxes/2,numboxes/2,RED,NOBOXIT);
plot(numboxes/2+1,numboxes/2+1,RED,NOBOXIT);
plot(numboxes/2+1,numboxes/2,BLACK,NOBOXIT);
plot(numboxes/2,numboxes/2+1,BLACK,NOBOXIT);
printstring(yourmove, 0, 0);
for (x = 0; x < numboxes+2; x++)
for (y = 0; y < numboxes+2; y++)
bonus[x][y] = 0;
for (x = 1; x < numboxes+1; x++)
for (y = 1; y < numboxes+1; y++)
bonus[x][y] = 3;
for (x = 2; x < numboxes; x++)
for (y = 2; y < numboxes; y++)
bonus[x][y] = -1;
for (x = 3; x < numboxes-1; x++)
for (y = 3; y < numboxes-1; y++)
bonus[x][y] = 0;
bonus[1][1] = bonus[numboxes][1] = 13;
bonus[numboxes][numboxes] = bonus[1][numboxes] = 13;
bonus[2][2] = bonus[numboxes-1][2] = -9;
bonus[numboxes-1][numboxes-1] = bonus[2][numboxes-1] = -9;
bonus[2][1] = bonus[numboxes-1][1] = -2;
bonus[1][2] = bonus[numboxes][2] = -2;
bonus[numboxes][numboxes-1] = bonus[1][numboxes-1] = -2;
bonus[numboxes-1][numboxes] = bonus[2][numboxes] = -2;
/* This is what the original bonus array looked like for an 8 by 8 game
board.
{ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 13, -2, 3, 3, 3, 3, -2, 13, 0 },
{ 0, -2, -9, -1, -1, -1, -1, -9, -2, 0 },
{ 0, 3, -1, 0, 0, 0, 0, -1, 3, 0 },
{ 0, 3, -1, 0, 0, 0, 0, -1, 3, 0 },
{ 0, 3, -1, 0, 0, 0, 0, -1, 3, 0 },
{ 0, 3, -1, 0, 0, 0, 0, -1, 3, 0 },
{ 0, -2, -9, -1, -1, -1, -1, -9, -2, 0 },
{ 0, 13, -2, 3, 3, 3, 3, -2, 13, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
}; */
/* Add a large enough number to make all the bonus value positive. */
for (x = 1; x < numboxes+1; x++)
for (y = 1; y < numboxes+1; y++)
bonus[x][y] += 9;
}